// Copyright 2024 FastLabs Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::sync::{Arc, RwLock, Weak};

use crate::Filter;

use super::FilterResult;

#[derive(Debug)]
pub struct ReloadFilter<F: Filter> {
    inner: Arc<RwLock<F>>,
}

pub struct Handle<F> {
    inner: Weak<RwLock<F>>,
}

impl<F: Filter> ReloadFilter<F> {
    pub fn new(filter: F) -> (Self, Handle<F>) {
        let this = Self {
            inner: Arc::new(RwLock::new(filter)),
        };

        let handle = this.handle();
        (this, handle)
    }

    fn handle(&self) -> Handle<F> {
        Handle {
            inner: Arc::downgrade(&self.inner),
        }
    }
}

impl<F: Filter> Handle<F> {
    pub fn modify(&self, f: impl FnOnce(&mut F)) -> Result<(), log::SetLoggerError> {
        let inner = self.inner.upgrade().unwrap();

        if let Ok(mut lock) = inner.try_write() {
            f(&mut *lock);
        }

        Ok(())
    }
}

impl<F: Filter> Filter for ReloadFilter<F> {
    fn enabled(&self, metadata: &log::Metadata) -> FilterResult {
        if let Ok(lock) = self.inner.read() {
            lock.enabled(metadata)
        } else {
            FilterResult::Reject
        }
    }

    fn matches(&self, record: &log::Record) -> FilterResult {
        if let Ok(lock) = self.inner.read() {
            lock.matches(record)
        } else {
            FilterResult::Reject
        }
    }
}
